﻿using Microsoft.Extensions.Logging;
using SkiaSharp;

namespace Devonline.AspNetCore;

/// <summary>
/// 图片操作相关服务基础服务
/// </summary>
/// <param name="logger"></param>
/// <param name="httpSetting"></param>
public abstract class BaseImageService(ILogger<BaseImageService> logger, HttpSetting httpSetting) : FileService(logger, httpSetting), IFileService
{
    /// <summary>
    /// 根据分辨率和格式重命名图片文件
    /// 格式说明: D: 目录名, R: 分辨率, F: 文件名, 其余部分只能是符号
    /// 格式示例: D/R/F -> 分辨率作为目录名后缀, 默认格式
    /// 格式示例: D/R_F -> 分辨率作为文件名前缀
    /// 格式示例: D/F_R -> 分辨率作为文件名后缀
    /// 格式示例: D_R_F -> 目录名, 分辨率都作为文件名前缀
    /// 格式示例: D(R)/F -> 分辨率作为目录名后缀
    /// </summary>
    /// <param name="imageFileName">图片文件名</param>
    /// <param name="outPath">输出目录</param>
    /// <param name="format">文件命名格式</param>
    /// <returns>输出文件名</returns>
    /// <exception cref="Exception"></exception>
    public virtual string Rename(string imageFileName, string? outPath = default, string? format = default)
    {
        ArgumentNullException.ThrowIfNull(imageFileName);
        using var image = SKBitmap.Decode(imageFileName);
        var extension = Path.GetExtension(imageFileName);

        //格式: R
        var resolution = $"{image.Width}x{image.Height}";
        //格式: D 
        var filePath = outPath ?? Path.GetDirectoryName(imageFileName);
        //格式: F
        var fileName = Path.GetFileNameWithoutExtension(imageFileName);
        if (fileName.Contains(resolution))
        {
            fileName = fileName.Replace(resolution, string.Empty);
        }

        format ??= "D/R/F";
        var indexDic = new Dictionary<char, int>();
        var index = format.IndexOf('D');
        if (index < 0)
        {
            index = int.MaxValue;
        }

        indexDic.Add('D', index);

        index = format.IndexOf('R');
        if (index < 0)
        {
            index = int.MaxValue;
        }

        indexDic.Add('R', index);

        index = format.IndexOf('F');
        if (index < 0)
        {
            index = int.MaxValue;
        }

        indexDic.Add('F', index);

        indexDic = indexDic.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
        var newFileName = format;
        foreach (var item in indexDic)
        {
            if (item.Value >= 0 && item.Value <= format.Length)
            {
                newFileName = newFileName[0..item.Value] + (item.Key switch
                {
                    'D' => filePath,
                    'R' => resolution,
                    'F' => fileName,
                    _ => string.Empty
                }) + newFileName[(item.Value + 1)..];
            }
        }

        newFileName += extension;
        filePath = Path.GetDirectoryName(newFileName);
        if (string.IsNullOrWhiteSpace(filePath))
        {
            throw new Exception($"{_userAccess}: the file path of {imageFileName} can not be null.");
        }

        if (!Directory.Exists(filePath))
        {
            Directory.CreateDirectory(filePath);
        }

        if (File.Exists(newFileName))
        {
            throw new Exception($"{_userAccess}: the file {newFileName} already exists.");
        }

        File.Move(imageFileName, newFileName);
        return newFileName;
    }

    /// <summary>
    /// 根据指定分辨率获取缩放后的文件名
    /// </summary>
    /// <param name="fileName">原始文件名</param>
    /// <returns></returns>
    /// <exception cref="DirectoryNotFoundException"></exception>
    protected virtual string GetNewFileName(string fileName, string flag)
    {
        var fileInfo = new FileInfo(fileName);
        var directory = fileInfo.DirectoryName;
        if (string.IsNullOrWhiteSpace(directory))
        {
            throw new DirectoryNotFoundException($"{_userAccess}: the file {fileName} directory error");
        }

        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }

        var newFileName = Path.Combine(directory, $"{Path.GetFileNameWithoutExtension(fileInfo.Name)}_{flag}{fileInfo.Extension}");
        return newFileName;
    }
    /// <summary>
    /// 将 解码并处理后的原图 保存到新文件
    /// </summary>
    /// <param name="image">解码并处理后的原图</param>
    /// <param name="fileName">保存文件名</param>
    protected static string Save(SKBitmap image, string fileName)
    {
        using var outputImage = SKImage.FromBitmap(image);
        using var data = outputImage.Encode(SKEncodedImageFormat.Png, 85);
        using var fileStream = File.Open(fileName, FileMode.OpenOrCreate);
        data.SaveTo(fileStream);
        fileStream.Close();
        return fileName;
    }
}